/* 
 * Include common header file for shared declarations and definitions
 * This header contains function prototypes and common data types used across the application
 */
#include "common.h"

/* 
 * Read entire file content into a dynamically allocated character buffer
 * This function opens a file, determines its size, allocates memory, and reads the complete content
 * 
 * @param filename Path to the file to be read
 * @return Pointer to allocated buffer containing file content, NULL on failure
 */
char *read_file(const char *filename)
{
    /* 
     * Declare file pointer for file operations
     * This variable will hold the reference to the opened file
     */
    FILE *fp = NULL;
    
    /* 
     * Variable to store the length of the file in bytes
     * Used to determine how much memory to allocate for file content
     */
    int length = 0;
    
    /* 
     * Pointer to dynamically allocated buffer for file content
     * This will store the complete content of the file as a string
     */
    char *content = NULL;
    
    /* 
     * Variable to track number of characters actually read from file
     * Ensures that the expected amount of data was successfully read
     */
    size_t read_chars = 0;

    /* 
     * Open file in read binary mode for platform-independent reading
     * Binary mode prevents any character translation during reading
     */
    /* open in read binary mode */
    fp = fopen(filename, "rb");
    
    /* 
     * Check if file opening operation was successful
     * If file cannot be opened, jump to cleanup section
     */
    if (fp == NULL)
    {
        goto cleanup;
    }

    /* 
     * Seek to end of file to determine total file size
     * Move file pointer to the end position of the file
     */
    /* get the length */
    if (fseek(fp, 0, SEEK_END) != 0)
    {
        goto cleanup;
    }
    
    /* 
     * Get current file position which represents file size
     * Retrieve the offset from beginning which equals file length
     */
    length = ftell(fp);
    
    /* 
     * Validate that file length retrieval was successful
     * Negative value indicates error in determining file size
     */
    if (length < 0)
    {
        goto cleanup;
    }
    
    /* 
     * Reset file pointer to beginning of file for reading
     * Reposition to start of file to prepare for content reading
     */
    if (fseek(fp, 0, SEEK_SET) != 0)
    {
        goto cleanup;
    }

    /* 
     * Allocate memory buffer for file content plus null terminator
     * Allocate length + 1 bytes to accommodate null terminator for string
     */
    /* allocate content buffer */
    content = (char *)malloc((size_t)length + sizeof(""));
    
    /* 
     * Check if memory allocation was successful
     * If allocation fails, jump to cleanup section
     */
    if (content == NULL)
    {
        goto cleanup;
    }

    /* 
     * Read entire file content into allocated buffer
     * Read exactly 'length' number of characters from file
     */
    /* read the file into memory */
    read_chars = fread(content, sizeof(char), (size_t)length, fp);
    
    /* 
     * Verify that expected number of characters were read
     * If read count doesn't match expected length, free buffer and cleanup
     */
    if ((int)read_chars != length)
    {
        free(content);
        content = NULL;
        goto cleanup;
    }
    
    /* 
     * Add null terminator to create proper C string
     * Ensure the content is properly terminated for string operations
     */
    content[read_chars] = '\0';

/* 
 * Cleanup section for resource management
 * This label handles proper cleanup of resources before function return
 */
cleanup:
    /* 
     * Close file pointer if it was successfully opened
     * Release file handle to prevent resource leaks
     */
    if (fp != NULL)
    {
        fclose(fp);
    }

    /* 
     * Return pointer to file content or NULL on failure
     * Caller is responsible for freeing the returned buffer
     */
    return content;
}

/* 
 * Check if specified file exists in the file system
 * This function verifies file existence using access system call
 * 
 * @param filepath Path to the file to check for existence
 * @return 0 if file exists, -1 if file doesn't exist or path is NULL
 */
int is_file_exist(const char *filepath)
{
    /* 
     * Validate input parameter is not NULL
     * Return error if null pointer is provided
     */
    if(filepath ==NULL)
        return -1;
    
    /* 
     * Use access system call with F_OK flag to check file existence
     * F_OK tests for existence of the file without considering permissions
     */
    if(access(filepath,F_OK)==0)
        return 0;
    
    /* 
     * Return error code indicating file does not exist
     * File cannot be found at the specified path
     */
    return -1;
}

/* 
 * Check if specified directory exists in the file system
 * This function verifies directory existence using access system call
 * 
 * @param dirpath Path to the directory to check for existence
 * @return 0 if directory exists, -1 if directory doesn't exist or path is NULL
 */
int is_dir_exist(const char *dirpath)
{
    /* 
     * Validate input parameter is not NULL
     * Return error if null pointer is provided
     */
    if(dirpath ==NULL)
        return -1;

    /* 
     * Use access system call with F_OK flag to check directory existence
     * F_OK tests for existence of the directory path
     */
    if(access(dirpath,F_OK) == 0)
    {
        return 0;
    }
    
    /* 
     * Return error code indicating directory does not exist
     * Directory cannot be found at the specified path
     */
    return -1;
}


/* 
 * Write character buffer content to specified file
 * This function creates or overwrites a file with the provided content
 * 
 * @param filename Path to the file to be written
 * @param buf Character buffer containing content to write
 * @return 0 on success, -1 on failure
 */
int write_file(const char *filename, const char *buf)
{
    /* 
     * Declare file pointer for file operations
     * This variable will hold the reference to the opened file
     */
    FILE *fp = NULL;
    
    /* 
     * Open file in write mode with truncation (create if not exists)
     * w+ mode creates new file or truncates existing file to zero length
     */
    if ((fp = fopen(filename, "w+")) != NULL)
    {
        /* 
         * Write entire buffer content to file in one operation
         * Write strlen(buf) characters as one element to the file
         */
        fwrite(buf, strlen(buf), 1, fp);
        
        /* 
         * Close file handle to ensure data is flushed to disk
         * Release system resources associated with file operations
         */
        fclose(fp);
    }
    else
    {
        /* 
         * Return error code if file opening failed
         * Indicates permission issues or invalid path
         */
        return -1;
    }
    
    /* 
     * Return success code indicating file was written successfully
     * Operation completed without errors
     */
    return 0;
}

/* 
 * Sleep for specified number of milliseconds
 * This function provides millisecond precision sleep functionality
 * 
 * @param ms Number of milliseconds to sleep
 */
void sleep_ms(unsigned int ms)
{
    /* 
     * Convert milliseconds to microseconds and call usleep
     * usleep provides microsecond precision sleep functionality
     */
    usleep(ms * 1000);
}

/* 
 * Sleep for specified number of seconds
 * This function provides second precision sleep functionality
 * 
 * @param s Number of seconds to sleep
 */
void sleep_s(unsigned int s)
{
    /* 
     * Call standard sleep function with second precision
     * Suspends execution for the specified number of seconds
     */
    sleep(s);
}

/* 
 * Execute shell command without capturing output
 * This function runs a system command and discards any output
 * 
 * @param cmd Shell command string to execute
 * @return 0 on success, -1 on failure
 */
int my_system(const char *cmd)
{
    /* 
     * Declare file pointer for pipe operations
     * Used to capture command output (though discarded in this implementation)
     */
    FILE *fp;
    
    /* 
     * Validate input command is not NULL
     * Return error if null command is provided
     */
    if (cmd == NULL)
    {
        return -1;
    }
    
    /* 
     * Execute command using popen and open read pipe
     * Command output is available through the pipe but not used
     */
    fp = popen(cmd, "r");
    
    /* 
     * Check if command execution was successful
     * Return error if popen failed to execute command
     */
    if (fp == NULL)
    {
        return -1;
    }
    
    /* 
     * Close pipe and wait for command to complete
     * Ensures proper cleanup of pipe resources
     */
    pclose(fp);
    
    /* 
     * Return success code indicating command was executed
     * Note: This doesn't indicate whether command succeeded, only that it ran
     */
    return 0;
}

/* 
 * Execute formatted shell command and return exit status
 * This function supports variable arguments and returns command exit status
 * 
 * @param fmt Format string for command with printf-style placeholders
 * @param ... Variable arguments for format string
 * @return Command exit status (0 typically indicates success)
 */
//返回执行命令后的状态值，一般0表示ok，其他表示异常
int shell_system(const char *fmt, ...)
{
    /* 
     * Variable to store command execution return status
     * Captures the exit status of the executed command
     */
    int ret;
    
    /* 
     * Buffer to store formatted command string
     * Fixed size buffer for command construction
     */
    char cmdbuffer[1024]={0};
    
    /* 
     * Variable argument list for handling variable arguments
     * Used to process the variable arguments passed to the function
     */
    va_list ap;
    
    /* 
     * Initialize variable argument list
     * Start processing variable arguments after fmt parameter
     */
	va_start(ap, fmt);
    
    /* 
     * Format command string with variable arguments
     * Construct the complete command string from format and arguments
     */
    ret=vsprintf(cmdbuffer,fmt,ap);
    
    /* 
     * Check if string formatting was successful
     * Negative return indicates formatting error
     */
    if(ret<0) 
    {
        /* 
         * Clean up variable argument list on error
         * End variable argument processing before returning
         */
        va_end(ap);
        return -1;
    }
    
    /* 
     * Execute the formatted command using system call
     * Run the constructed command in system shell
     */
    ret=system(cmdbuffer);
    
    /* 
     * Clean up variable argument list
     * End variable argument processing after command execution
     */
    va_end(ap);
    
    /* 
     * Extract and return command exit status
     * WEXITSTATUS macro extracts the exit code from system return value
     */
    return WEXITSTATUS(ret);
}

/* 
 * Execute formatted shell command and capture output
 * This function runs a command and reads the first line of output into buffer
 * 
 * @param buf Output buffer to store command output
 * @param size Size of output buffer to prevent overflow
 * @param fmt Format string for command with printf-style placeholders
 * @param ... Variable arguments for format string
 * @return 0 on success, -1 on failure
 */
int shell_popen(char *buf,int size,const char *fmt, ...)
{
    /* 
     * File pointer for pipe operations
     * Used to read command output through pipe
     */
    FILE *fp;
    
    /* 
     * Variable to store function return status
     * Tracks success or failure of various operations
     */
    int ret;
    
    /* 
     * Buffer to store formatted command string
     * Fixed size buffer for command construction
     */
    char cmdbuffer[1024]={0};
    
    /* 
     * Variable argument list for handling variable arguments
     * Used to process the variable arguments passed to the function
     */
    va_list ap;
    
    /* 
     * Initialize variable argument list
     * Start processing variable arguments after fmt parameter
     */
	va_start(ap, fmt);
    
    /* 
     * Format command string with variable arguments
     * Construct the complete command string from format and arguments
     */
    ret=vsprintf(cmdbuffer,fmt,ap);
    
    /* 
     * Clean up variable argument list
     * End variable argument processing after command formatting
     */
    va_end(ap);
    
    // printf("cmdbuffer=%s\n",cmdbuffer);
    
    /* 
     * Check if string formatting was successful
     * Negative return indicates formatting error
     */
    if(ret<0) return -1;;
    
    /* 
     * Execute command and open read pipe for output
     * Create pipe to capture command standard output
     */
    fp = popen(cmdbuffer, "r");
    
    /* 
     * Check if command execution and pipe creation was successful
     * Return error if popen failed to execute command
     */
    if (fp == NULL)
    {
        return -1;
    }
    
    /* 
     * Read first line of command output into buffer
     * fgets reads up to size-1 characters or until newline
     */
    if(fgets(buf,size,fp)==NULL)
    {
        /* 
         * Set error return if no output was read
         * Command may have produced no output or error occurred
         */
        ret=-1;
    }
    else
    {
        /* 
         * Set success return if output was successfully read
         * Buffer contains command output line
         */
        ret=0;
    }
        // printf("fgets=%s\n",buf);
    
    /* 
     * Close pipe and wait for command to complete
     * Ensures proper cleanup of pipe resources
     */
    pclose(fp);
    
    /* 
     * Return operation status (0 success, -1 failure)
     * Indicates whether command output was successfully captured
     */
    return ret;
}


/* 
 * Get current system time in milliseconds since epoch
 * This function provides millisecond precision timestamp
 * 
 * @return Current time as milliseconds since Unix epoch
 */
long long get_system_time_ms(void)
{
    /* 
     * Variable to store calculated time in milliseconds
     * 64-bit integer to prevent overflow with large time values
     */
    long long time_ms;

    /* 
     * Structure to store time values with microsecond precision
     * gettimeofday provides seconds and microseconds components
     */
    struct timeval tv;
    
    /* 
     * Get current time with microsecond precision
     * Populates tv structure with current system time
     */
    gettimeofday(&tv, NULL);
    
    /* 
     * Convert seconds to milliseconds and add microseconds converted to milliseconds
     * Combine both components to get total milliseconds
     */
    time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;

    /* 
     * Return calculated milliseconds timestamp
     * Provides current time reference for timing operations
     */
    return time_ms;
}

/* 
 * Get current system time in microseconds since epoch
 * This function provides microsecond precision timestamp
 * 
 * @return Current time as microseconds since Unix epoch
 */
u64 get_system_time_us(void)
{
    /* 
     * Structure to store time values with microsecond precision
     * gettimeofday provides seconds and microseconds components
     */
    struct timeval now;
    
    /* 
     * Get current time with microsecond precision
     * Populates now structure with current system time
     */
    gettimeofday(&now, NULL);
    
    /* 
     * Convert seconds to microseconds and add microseconds component
     * Combine both components to get total microseconds
     */
    return now.tv_sec * 1000000LL + now.tv_usec;
}

/* 
 * Calculate absolute time difference between two microsecond timestamps
 * This function handles timestamp wrap-around correctly
 * 
 * @param current Current timestamp in microseconds
 * @param last Previous timestamp in microseconds
 * @return Absolute time difference in microseconds
 */
u64 get_system_time_absoffset(u64 current, u64 last)
{
    /* 
     * Check if current timestamp is greater than or equal to last timestamp
     * Normal case where time has advanced normally
     */
    if (current >= last)
        /* 
         * Return simple difference when no wrap-around occurred
         * Standard time difference calculation
         */
        return (current - last);
    else
        /* 
         * Handle timestamp wrap-around case
         * Calculate difference accounting for counter overflow
         */
        return (u64)((0xffffffffffffffff - last) + current);
}

/* 
 * Get current minute of the hour from system time
 * This function extracts the minute component from current time
 * 
 * @return Current minute (0-59) of the hour
 */
int system_minute(void)
{
    /* 
     * Get current calendar time as seconds since epoch
     * time(NULL) returns current time in seconds
     */
    time_t t = time(NULL);
    
    /* 
     * Convert calendar time to broken-down local time
     * localtime converts time_t to struct tm with separate time components
     */
    struct tm *t1 = localtime(&t);

    /* 
     * Return minute component from broken-down time structure
     * Extracts tm_min field which represents minutes (0-59)
     */
    return t1->tm_min;
}

/* 
 * Convert character string to integer value
 * This function safely converts string representation to integer
 * 
 * @param ch Character string containing integer representation
 * @return Integer value, 0 if input is NULL
 */
int char_to_int(char *ch)
{
    /* 
     * Check if input string pointer is not NULL
     * Prevent null pointer dereference in conversion
     */
    if (ch)
    {
        /* 
         * Convert string to integer using standard atoi function
         * atoi converts ASCII string to integer representation
         */
        return atoi(ch);
    }
    
    /* 
     * Return default value 0 if input is NULL
     * Safe fallback for null input parameter
     */
    return 0;
}

/* 
 * Convert integer value to character string
 * This function converts integer to string representation
 * 
 * @param value Integer value to convert
 * @param ch Output buffer for string representation
 */
void int_to_char(int value, char *ch)
{
    /* 
     * Convert integer to string using sprintf function
     * Format integer as decimal string in output buffer
     */
    sprintf(ch, "%d", value);
    //itoa(value, ch, 10);
}

/* 
 * Convert character string to floating-point value
 * This function safely converts string representation to float
 * 
 * @param ch Character string containing float representation
 * @return Float value, 0.0 if input is NULL
 */
float char_to_float(char *ch)
{
    /* 
     * Check if input string pointer is not NULL
     * Prevent null pointer dereference in conversion
     */
    if (ch)
    {
        /* 
         * Convert string to float using standard atof function
         * atof converts ASCII string to floating-point representation
         */
        return atof(ch);
    }
    
    /* 
     * Return default value 0.0 if input is NULL
     * Safe fallback for null input parameter
     */
    return 0.0f;
}

/**
 * @brief Split string into tokens using specified separator
 * This function tokenizes a string by splitting at each occurrence of separator
 * 
 * @param src Source string to be split (will be modified)
 * @param separator Character used as delimiter for splitting
 * @param dest Array of pointers to receive token strings
 * @param num Pointer to integer that will receive token count
 */
void split(char *src, const char *separator, char **dest, int *num)
{
    /* 
     * Pointer to track current token during string splitting
     * Used by strtok to maintain tokenization state
     */
    char *pNext;
    
    /* 
     * Counter for number of tokens found
     * Incremented for each token extracted from source string
     */
    int count = 0;

    /* 
     * Validate source string is not NULL and has content
     * Return early if source string is invalid or empty
     */
    if (src == NULL || strlen(src) == 0)
        return;

    /* 
     * Validate separator string is not NULL and has content
     * Return early if separator is invalid or empty
     */
    if (separator == NULL || strlen(separator) == 0)
        return;

    /* 
     * Get first token from source string using strtok
     * strtok modifies the source string by replacing separators with null bytes
     */
    pNext = (char *)strtok(src, separator); /* cast to char* */
    
    /* 
     * Loop through all tokens in the source string
     * Continue until strtok returns NULL indicating no more tokens
     */
    while (pNext != NULL)
    {
        /* 
         * Store pointer to current token in destination array
         * Increment destination pointer for next token
         */
        *dest++ = pNext;
        
        /* 
         * Increment token counter
         * Track total number of tokens extracted
         */
        ++count;
        
        /* 
         * Get next token from source string
         * NULL argument tells strtok to continue from previous position
         */
        pNext = (char *)strtok(NULL, separator);
    }
    
    /* 
     * Store final token count in output parameter
     * Provides caller with number of tokens found
     */
    *num = count;
}